package cn.ysnk.generateCode;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.commons.lang3.StringUtils;

import com.jfinal.kit.PathKit;
import com.jfinal.kit.PropKit;
import com.jfinal.plugin.activerecord.ActiveRecordException;
import com.jfinal.plugin.activerecord.Config;
import com.jfinal.plugin.activerecord.DbKit;

import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateException;

public class TabelGenerator {
	private static String SHOW_COLUNM_INFO = "select column_name,column_type,IS_NULLABLE,COLUMN_KEY,COLUMN_COMMENT from INFORMATION_SCHEMA.Columns where table_name='GENERATOR_TABLE_NAME' ";
	private static Configuration config;
	static{
		try {
			config = new Configuration();
			PropKit.use("a_little_config.txt");
			Class.forName("com.mysql.jdbc.Driver");
			config.setDirectoryForTemplateLoading(new File(MyStringUtil.getTemplatePath()));
		} catch (IOException e) {
			e.printStackTrace();
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}
	}
	
	
	/**
	 * 根据表名生成实体类
	 * @param tabelName 表的名称
	 * @param searchColumn  用于查询的列 
	 * @param formColumns  用于生成表单的列 请用英文逗号隔开
	 * @param listColumns	用于展示在列表的列 请用英文逗号隔开
	 * @return
	 * author：夏尉
	 * @throws SQLException 
	 */
	private static EntityModel generateEntityModel(String tabelName,String searchFiled,String formColumns,String listColumns) throws SQLException{
		Config config = DbKit.getConfig();
		Connection conn = null;
		PreparedStatement colunmsPs = null;
		ResultSet columnsRs = null;
		List<EntityColumn> colunms = new ArrayList<EntityColumn>();
		EntityColumn primaryColumn = null;
		EntityColumn searchColumn = null;
		try{
			conn = config.getConnection();
			colunmsPs = conn.prepareStatement(SHOW_COLUNM_INFO.replace("GENERATOR_TABLE_NAME", tabelName));
			columnsRs = colunmsPs.executeQuery();
			// 获取对应表中的字段
			while (columnsRs.next()) {
				//字段名称
				String columnName = columnsRs.getString(1);
				String type = columnsRs.getString(2);
				type = type.replaceAll("/(/d+/)", "");
				ColumnEnum columnEnum = ColumnEnum.switch2ColumnEnum(type);
				boolean isPrimaryKey = false;
				//是否主键
				String primarykey = columnsRs.getString(4);
				if (StringUtils.isNotEmpty(primarykey) && StringUtils.equals(primarykey, "PRI")) {
					isPrimaryKey = true;
				}
				String commont = columnsRs.getString(5)==null?"":columnsRs.getString(5);
				boolean isSearchColumn = false;
				if(MyStringUtil.isNotNull(searchFiled)){
					if(searchFiled.indexOf(columnName)>=0){
						isSearchColumn = true;	
					}
				}
				
				boolean isFormField = false;
				if(MyStringUtil.isNotNull(formColumns)){
					if(formColumns.indexOf(columnName)>=0){
						isFormField = true;	
					}
				}
				
				boolean isListColumn = false;
				if(MyStringUtil.isNotNull(listColumns)){
					if(listColumns.indexOf(columnName)>=0){
						isListColumn = true;	
					}
				}
				
				boolean nullAble = "YES".equals(columnsRs.getString(3));
				
				EntityColumn entityColumn =  new EntityColumn(isPrimaryKey, isFormField, isListColumn,nullAble, commont, columnEnum, columnName);
				
				if(isPrimaryKey){
					primaryColumn = entityColumn;
				}else{
					if(isSearchColumn)
						searchColumn = entityColumn;
					colunms.add(entityColumn);
				}
			}
			
			EntityModel em = new EntityModel( tabelName,colunms,primaryColumn,searchColumn);
			return em;
		} catch (Exception e) {
			throw new ActiveRecordException(e);
		} finally {
			config.close(columnsRs,colunmsPs, conn);
		}
	}
	
	/**
	 * 通过表生成entity、controller、jsp
	 * @param name 实体名称，比如商品、订单等
	 * @param controllerUrl controller的url
	 * @param tableName 表名
	 * @param searchFiled	查询字段
	 * @param formColumns  表单过滤字段,即不会生成表单输入控件，用英文逗号隔开
	 * @param listColumns  列表展示字段，
	 * author：夏尉
	 * @throws SQLException 
	 */
	public static void generateTable(String name,String controllerUrl,String tableName,String searchFiled,String formColumns,String listColumns,String projectPath){
//		GenerateCodeAuthPrint.print();
		PropKit.use("a_little_config.txt");
		String baseEntityPath = projectPath + "/" +PropKit.get("sourceDir")+"/"+ PropKit.get("entityScannerPath").replace(".", "/");
		String baseControllerPath = projectPath + "/" +PropKit.get("sourceDir")+"/"+ PropKit.get("controllerScannerPath").replace(".", "/");
		String baseJspPath = projectPath + "/" +PropKit.get("jspDir"); //System.getProperty("user.dir")
		try {
			EntityModel model = generateEntityModel(tableName, searchFiled, formColumns, listColumns);
			System.out.println("正在生产实体类"+PropKit.get("entityScannerPath")+"."+model.getEntityFileName()+"."+model.getUpEntityFileName());
			generatorEntity(name,model, baseEntityPath);
			System.out.println("实体类生成成功");
			System.out.println("正在生产controller类"+PropKit.get("controllerScannerPath")+"."+model.getControllerFileName()+"."+model.getUpControllerFileName());
			generatorController(name,model, baseControllerPath,controllerUrl);
			System.out.println("controller生成成功");
			System.out.println("正在生产webapp/"+model.getEntityFileName()+"/view.jsp页面");
			generateViewJsp(name,model, baseJspPath, controllerUrl);
			System.out.println("view.jsp生成成功");
			System.out.println("正在生产webapp/"+model.getEntityFileName()+"/edit.jsp页面");
			generateEditJsp(name,model, baseJspPath, controllerUrl);
			System.out.println("edit.jsp生成成功");
		} catch (IOException | TemplateException e) {
			e.printStackTrace();
		} catch (SQLException e) {
			e.printStackTrace();
		}
	}
	
	private static void generatorEntity(String name,EntityModel model,String baseEntityPath){
		try{
			Template template = config.getTemplate("entity.ftl");
			ConcurrentMap<String, Object> modelMap = new ConcurrentHashMap<String, Object>();
			modelMap.put("name", name);
			modelMap.put("model", model);
			modelMap.put("packageName", PropKit.get("entityScannerPath")+"."+model.getEntityFileName());
			File entityFolder = new File(baseEntityPath+"/"+model.getEntityFileName());
			if (!entityFolder.exists()) {
				entityFolder.mkdirs();
			}
			template.process(modelMap,
					new FileWriter(new File(baseEntityPath + "/" +model.getEntityFileName()+"/" + model.getUpEntityFileName() + ".java")));
		}catch(Exception e){
			e.printStackTrace();
			System.out.println("生成实体类失败(%>_<%)");
		}
	}
	
	private static void generatorController(String name,EntityModel model,String baseEntityPath,String controllerUrl) throws IOException, TemplateException{
		try{
			Template template = config.getTemplate("controller.ftl");
			ConcurrentMap<String, Object> modelMap = new ConcurrentHashMap<String, Object>();
			modelMap.put("model", model);
			modelMap.put("name", name);
			modelMap.put("packageName", PropKit.get("controllerScannerPath")+"."+model.getControllerFileName());
			modelMap.put("entityPackage",PropKit.get("entityScannerPath")+"."+model.getEntityFileName());
			modelMap.put("controllerUrl",controllerUrl);
			File entityFolder = new File(baseEntityPath+"/"+model.getControllerFileName());
			if (!entityFolder.exists()) {
				entityFolder.mkdirs();
			}
			template.process(modelMap,
					new FileWriter(new File(baseEntityPath + "/" +model.getControllerFileName()+"/" + model.getUpControllerFileName() + ".java")));
		}catch(Exception e){
			e.printStackTrace();
			System.out.println("生成conroller类失败(%>_<%)");
		}
	}
	
	private static void generateViewJsp(String name,EntityModel model,String baseEntityPath,String controllerUrl) throws IOException, TemplateException{
		try{
			Template template = config.getTemplate("view.ftl");
			ConcurrentMap<String, Object> modelMap = new ConcurrentHashMap<String, Object>();
			modelMap.put("model", model);
			modelMap.put("name", name);
			modelMap.put("packageName", PropKit.get("controllerScannerPath")+"."+model.getControllerFileName());
			modelMap.put("entityPackage",PropKit.get("entityScannerPath")+"."+model.getEntityFileName());
			modelMap.put("controllerUrl",controllerUrl);
			File entityFolder = new File(baseEntityPath+"/"+model.getBaseEntityName());
			if (!entityFolder.exists()) {
				entityFolder.mkdirs();
			}
			template.process(modelMap,
					new FileWriter(new File(baseEntityPath + "/" +model.getBaseEntityName()+"/view.jsp")));
		}catch(Exception e){
			e.printStackTrace();
			System.out.println("生成view.jsp失败了(%>_<%)");
		}
	}
	
	private static void generateEditJsp(String name,EntityModel model,String baseEntityPath,String controllerUrl) throws IOException, TemplateException{
		try{
			Template template = config.getTemplate("edit.ftl");
			ConcurrentMap<String, Object> modelMap = new ConcurrentHashMap<String, Object>();
			modelMap.put("model", model);
			modelMap.put("name", name);
			modelMap.put("packageName", PropKit.get("controllerScannerPath")+"."+model.getControllerFileName());
			modelMap.put("entityPackage",PropKit.get("entityScannerPath")+"."+model.getEntityFileName());
			modelMap.put("controllerUrl",controllerUrl);
			File entityFolder = new File(baseEntityPath+"/"+model.getBaseEntityName());
			if (!entityFolder.exists()) {
				entityFolder.mkdirs();
			}
			template.process(modelMap,
					new FileWriter(new File(baseEntityPath + "/" +model.getBaseEntityName()+"/edit.jsp")));
		}catch(Exception e){
			e.printStackTrace();
			System.out.println("生成edit.jsp失败了(%>_<%)");
		}
	}
	
}
